package com.lwp.excel.resolver.impl;


import com.lwp.excel.annotation.Cell;
import com.lwp.excel.resolver.ExcelAble;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.util.CellRangeAddress;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * Copyright (C) @2019 GuangDong Eshore Technology Co. Ltd
 *
 * @author: Administrator
 * @version: 1.0
 * @date: 2019/8/13
 * @time: 10:07
 * @description: 解析表头
 */
public class HeaderExcelResolver extends TitleExcelResolver {

    private Integer maxFieldRowSize;

    private Integer startRowIndex;

    public String[] headers;

    public Map<String,Object> headerMap;

    public Map<String,Object> tempHeaderMap;

    public Map<String, Object> getTempHeaderMap() {
        Map<String,Object> map = new HashMap<>();
        if (tempHeaderMap != null) {
            map = new HashMap<>();
            for (String key :
                    tempHeaderMap.keySet()) {
                map.put(key, tempHeaderMap.get(key));
            }
        }
        return map;
    }

    public void setTempHeaderMap(Map<String, Object> tempHeaderMap) {
        this.tempHeaderMap = tempHeaderMap;
    }

    public HeaderExcelResolver() {
    }

    public HeaderExcelResolver(Class<?> group,String[] headers,String title) {
        super(group,title);
        this.headers = headers;
        setHeaderMap(headers);
    }

    public void initTempHeaderMap(String fieldName){
        if (fieldName == null || fieldName.equals("")) {
            tempHeaderMap = headerMap;
        } else {
            if (tempHeaderMap != null) {
                tempHeaderMap = (Map<String, Object>) tempHeaderMap.get(fieldName);
            }
        }

    }

    /**
     * @param sheet
     * @param dataList
     * @param wb
     */
    public void headerResolver(HSSFSheet sheet, List<?> dataList, HSSFWorkbook wb) {
        Object data = dataList.get(0);
        Class clazz = data.getClass();//获取填充对象的Class对象，进行反射
        tempHeaderMap = headerMap;
        startRowIndex = lastRowIndex(sheet) - 1;
        headerResolver(sheet,clazz,wb,0,startRowIndex,new HeaderExcelResolver(group,headers,null));
    }

    /**
     * 解析表头
     * 1.获取最后一个需要添加的行
     * 2.创建行
     * 遍历字段；
     * 3.验证字段：
     *      1>验证字段是否被@Cell注解。
     *      2>验证是否有Group，有Group，值生成对应的Group
     *      3>验证是否有header，有header，值是否有该字段。
     *      以上三种验证都通过才能算通过，该字段才能显示。
     * 4.添加数据
     *       1> 获取最后一个需要添加的列
     *       2> 添加数据
     * 5.写入Style
     *
     * 6.验证是否是子集列表，或子集实体
     *    1> 子集递归解析。
     *    2> 不是自己准备继续。
     * 7.获取该字段占用多少单元格
     * 8.合并单元格。
     * 9.如果是子集列表或者实体，递归解析。
     * 遇到子集怎么办？遇到自己列表，则递归调用生成列。
     * @param sheet
     * @param clazz
     * @param wb
     */
    public void headerResolver(HSSFSheet sheet, Class<?> clazz, HSSFWorkbook wb,
                               int parentInsertCellIndex,int parentRowIndex,HeaderExcelResolver headerExcelResolver) {
        if (maxFieldRowSize == null) {
            maxFieldRowSize = countParticleRow(clazz,headers,headerExcelResolver);
        }
        Field[] fields = clazz.getDeclaredFields();//获取全部的字段
        int insertRowIndex = parentRowIndex + 1;//lastRowIndex(sheet);
        HSSFRow row = sheet.getRow(insertRowIndex);//sheet.createRow(insertRowIndex);
        if (row == null) {
            row = sheet.createRow(insertRowIndex);
        }
        row.setHeightInPoints(18);
        int lastFeildCellSize = 1;
        HSSFCellStyle style = wb.createCellStyle();
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
        //遍历字段
        for (Field field :
                fields) {
            //3.验证字段：
            if (!verifyField(field,headerExcelResolver)) {//验证没有通过
                continue;
            }
            //4.添加数据：1> 获取最后一个需要添加的列
            int insertCellIndex = lastCellIndex(row)+lastFeildCellSize-1;
            //2> 添加数据
            if (insertCellIndex <= parentInsertCellIndex) {
                insertCellIndex = parentInsertCellIndex;
            }
            HSSFCell cell = row.createCell(insertCellIndex);
            Cell cellAnnotation = field.getAnnotation(Cell.class);
            String cellValue = cellAnnotation.value();//获取表头
            cell.setCellValue(cellValue);//添加数据。
            //5.写入Style
            cell.setCellStyle(style);//设置样式，水平垂直居中。
            //6.验证是否是子集列表，或子集实体
            Class genericType = null;
            if (ExcelAble.class.isAssignableFrom(field.getType())) { //子集实体
                genericType = field.getType();
            } else if (Collection.class.isAssignableFrom(field.getType())) { //子集列表。
                Type type = field.getGenericType();
                if (type == null) continue;
                //得到泛型类型的类名
                if (type instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) type;
                    //得到泛型里的class类型对象
                    genericType = (Class<?>) parameterizedType.getActualTypeArguments()[0];
                }
            }
            //7.获取该字段占用多少单元格
            int fieldRowSize = 1;
            if (genericType == null) {
                fieldRowSize = countParticleRow(clazz,headers,headerExcelResolver); //获取行数。
                if (insertRowIndex + fieldRowSize - 1 < startRowIndex + maxFieldRowSize) {
                    fieldRowSize = startRowIndex + maxFieldRowSize - insertRowIndex + 1;

                }
            }
            //获取字段需要的列数
            int fieldCellSize = 1;
            HeaderExcelResolver cellHeaderResolver = new HeaderExcelResolver(group,headers,null);
            if (genericType == null) {
                fieldCellSize = countParticleCell(field.getType(),headers,cellHeaderResolver);
            } else {
                cellHeaderResolver.setTempHeaderMap((HashMap<String,Object>)headerExcelResolver.getTempHeaderMap().get(field.getName()));
                fieldCellSize = countParticleCell(genericType,headers,cellHeaderResolver);

            }
            lastFeildCellSize = fieldCellSize;
            //8.合并单元格。
            sheet.addMergedRegion(new CellRangeAddress(//合并单元格。
                    insertRowIndex, // 起始行
                    insertRowIndex+fieldRowSize-1, // 结束行
                    insertCellIndex, // 起始列
                    insertCellIndex+fieldCellSize-1  // 结束列
            ));
            //9.如果是子集列表或者实体，递归解析。
            if (genericType != null) {//拥有子集
                HeaderExcelResolver itemResolver = new HeaderExcelResolver(group,headers,null);
                itemResolver.setTempHeaderMap((HashMap<String,Object>)headerExcelResolver.getTempHeaderMap().get(field.getName()));
                headerResolver(sheet, genericType, wb,(insertCellIndex),insertRowIndex,itemResolver);
            }
        }
    }



    /**
     * 1.验证字段：
     *      1>验证字段是否被@Cell注解。
     *      2>验证是否有Group，有Group，值生成对应的Group
     *      3>验证是否有header，有header，值是否有该字段。
     *      以上三种验证都通过才能算通过，该字段才能显示。
     * @param field
     * @param headerExcelResolver
     * @return
     */
    public boolean verifyField(Field field, HeaderExcelResolver headerExcelResolver){
        Cell cell = field.getAnnotation(Cell.class);//获取Cell注解
        if (cell == null) {
            return false;
        }
        Class<?>[] groups = cell.groups();
        if (group != null) {
            if (groups == null || groups.length == 0) {
                return false;
            }
            if (!contatins(groups,group)) {//没有找到
                return false;
            }
        }
        if (!contains(field.getName(),headerExcelResolver)) {
            return false;
        }
        return true;
    }

    public boolean contatins(Class<?>[] groups,Class<?> group){
        return indexOf(groups,group) >= 0;
    }

    private int indexOf(Class<?>[] groups, Class<?> group) {
        if (group == null) {
            for (int i = 0; i < groups.length; i++) {
                if (groups[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < groups.length; i++) {
                if (group.equals(groups[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 查找元素是否存在
     * @param header
     * @param headerExcelResolver
     * @return
     */
    public boolean contains(String header, HeaderExcelResolver headerExcelResolver){
        String []headers = getHeaders(headerExcelResolver);
        if (headers == null || headers.length == 0) {//没有元素，直接不筛选。
            return true;
        }
        return indexOf(header,headers) >= 0;
    }

    private String[] getHeaders(HeaderExcelResolver headerExcelResolver) {
        String []headers = null;
        if (headerExcelResolver.tempHeaderMap!=null) {
            headers = new String[headerExcelResolver.tempHeaderMap.size()];
            int i = 0;
            for (String key :
                    headerExcelResolver.tempHeaderMap.keySet()) {
                headers[i] = key;
                i++;
            }
            return headers;
        }
        return headers;

    }


    /**
     * 获取元素的索引
     * 如果不存在则返回-1
     * @param header
     * @return
     */
    public int indexOf(String header) {
        if (header == null) {
            for (int i = 0; i < headers.length; i++) {
                if (headers[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < headers.length; i++) {
                if (header.equals(headers[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 获取元素的索引
     * 如果不存在则返回-1
     * @param header
     * @return
     */
    public int indexOf(String header,String [] headers) {
        if (header == null) {
            for (int i = 0; i < headers.length; i++) {
                if (headers[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < headers.length; i++) {
                if (header.equals(headers[i])) {
                    return i;
                }
            }
        }
        return -1;
    }


    public static void main(String[] args) {
        String[] keys = new String[] {"key1","key2","key3","key4","key4.key1","key4.key2","key4.key3.k1","key4.key3.k2","key4.key3.k3"};

        //Map<String, Object> map = new HeaderExcelResolver().setHeaderMap(keys);
        //System.out.println(map);

    }

    public void setHeaderMap(String [] headers){
        Map<String, Object> headersMap = new HashMap<>();
        if (headers != null) {
            for (int i = 0; i < headers.length; i++) {
                addMap(headers[i],headersMap);
            }
            this.headerMap = headersMap.size()>0?headersMap:null;
            this.tempHeaderMap = this.headerMap;
        }
    }

    public void addMap (String val,Map<String,Object> map){
        if (map == null) {
            map = new HashMap<>();
        }
        if (val.indexOf(".") == -1) {//首层
            map.put(val, null);
        } else {//不是首层
            String key = val.substring(0, val.indexOf("."));
            Map<String, Object> itemMap = (Map<String, Object>) map.get(key);
            if (itemMap == null) {
                itemMap = new HashMap<>();
            }
            addMap(val.substring(val.indexOf(".")+1),itemMap);
            map.put(key,itemMap);
        }
    }



}
